#region Using Statements
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Collections;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
#endregion

#region License
//-----------------------------------------------------------------------------
// Copyright (c) 2008, Aaron MacDougall, Daniel Jeffery
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of Aaron MacDougall or Daniel Jeffery nor the names of its contributors may
//   be used to endorse or promote products derived from this software without
//   specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------
#endregion

namespace Agro2DPipeline
{
    /// <summary>
    /// Various static methods to load sprite information, common to importers.
    /// </summary>
    internal class SpriteImport
    {
        /// <summary>
        /// Loads SpriteInfo structures from an XmlElement.
        /// </summary>
        /// <param name="spritesRoot">XmlElement in XML file</param>
        /// <param name="spriteInfoList">List of spriteInfo structures to load</param>
        public static void LoadSprites(XmlElement spritesRoot, ref List<SpriteInfo> spriteInfoList)
        {     
            foreach(XmlNode sprite in spritesRoot.ChildNodes)
            {
                XmlElement childElement = sprite as XmlElement;
                if(childElement == null)
                    continue;

                SpriteInfo spriteInfo = new SpriteInfo();
                spriteInfo.TypeName = sprite.LocalName;

                foreach (XmlAttribute attribute in childElement.Attributes)
                    spriteInfo.Properties[attribute.Name] = attribute.Value;

                foreach(XmlNode node in childElement.ChildNodes)
                {
                    XmlElement childElement2 = node as XmlElement;
                    if(childElement2 == null)
                        continue;

                    if(childElement2.Name == "SpriteProperties")
                    {
                        foreach(XmlAttribute attribute in childElement2.Attributes)
                            spriteInfo.SpriteProperties[attribute.Name] = attribute.Value;
                    }

                    if(childElement2.Name == "CollisionProperties")
                    {
                        foreach(XmlAttribute attribute in childElement2.Attributes)
                            spriteInfo.CollisionProperties[attribute.Name] = attribute.Value;
                    }

                    // Animation container.
                    if(childElement2.Name == "AnimationContainer")
                    {
                        spriteInfo.Animation = LoadAnimations(childElement2, ref spriteInfo.Animation);
                        if(spriteInfo.Animation.TypeName != "" && spriteInfo.Animation.TypeName != string.Empty)
                            spriteInfo.HasAnimation = true;
                    }

                    if(childElement2.Name == "Animation")
                    {
                        spriteInfo.Animation = LoadSingleAnimation(childElement2, ref spriteInfo.Animation);
                        if(spriteInfo.Animation.TypeName != "" && spriteInfo.Animation.TypeName != string.Empty)
                            spriteInfo.HasAnimation = true;
                    }
                }

                if(spriteInfo != null)
                    spriteInfoList.Add(spriteInfo);
            }
        }

        public static AnimationInfo LoadSingleAnimation(XmlElement animationElement, ref AnimationInfo parentInfo)
        {
            AnimationInfo animInfo = new AnimationInfo();
            

            //foreach(XmlAttribute attribute in animationElement.Attributes)
            //    animInfo.Properties[attribute.Name] = attribute.Value;
            
            XmlElement nestedAnimElement = animationElement.ChildNodes[0] as XmlElement;
            if(nestedAnimElement == null)
                return null;

            animInfo.TypeName = nestedAnimElement.LocalName;

            foreach(XmlAttribute attribute in nestedAnimElement.Attributes)
                animInfo.Properties[attribute.Name] = attribute.Value;

            return animInfo;
        }

        public static AnimationInfo LoadAnimations(XmlElement animationElement, ref AnimationInfo parentInfo)
        {
            Console.WriteLine("Hello?");
            if(animationElement.LocalName == "AnimationContainer")
            {
                AnimationInfo animInfo = new AnimationInfo();
                animInfo.TypeName = animationElement.LocalName;

                foreach(XmlAttribute attribute in animationElement.Attributes)
                    animInfo.Properties[attribute.Name] = attribute.Value;

                foreach(XmlNode nestedAnimNode in animationElement.ChildNodes)
                {
                    XmlElement nestedAnimElement = nestedAnimNode as XmlElement;
                    if(nestedAnimElement == null)
                        continue;

                    LoadAnimations(nestedAnimElement, ref animInfo);
                }

                if(parentInfo != null && parentInfo.TypeName == "Action")
                    parentInfo.NestedAnimations.Add(animInfo);

                return animInfo;
                
            }
            else
            {
                AnimationInfo animInfo = new AnimationInfo();
                animInfo.TypeName = animationElement.LocalName;                

                foreach(XmlAttribute attribute in animationElement.Attributes)
                    animInfo.Properties[attribute.Name] = attribute.Value;

                if(animInfo.TypeName == "Action")
                {
                    foreach(XmlNode nestedAnimNode in animationElement.ChildNodes)
                    {
                        XmlElement nestedAnimElement = nestedAnimNode as XmlElement;
                        if(nestedAnimElement == null)
                            continue;

                        LoadAnimations(nestedAnimElement, ref animInfo);
                    }
                }

                parentInfo.NestedAnimations.Add(animInfo); // Add animation.
                return animInfo;
            }           

        }

        /// <summary>
        /// Write sprites to xnb data with ContentWriter from a list of SpriteInfo structures.
        /// </summary>
        /// <param name="output">XNA ContentWriter</param>
        /// <param name="spriteInfoList">List of SpriteInfo structures to read from</param>
        public static void WriteSprites(ContentWriter output, ref List<SpriteInfo> spriteInfoList)
        {
            output.Write(spriteInfoList.Count);
            foreach(SpriteInfo spriteInfo in spriteInfoList)
            {
                WriteString(output, spriteInfo.TypeName);

                output.Write(spriteInfo.Properties.Keys.Count);
                foreach(string standardProp in spriteInfo.Properties.Keys)
                {
                    WriteString(output, standardProp);
                    WriteString(output, spriteInfo.Properties[standardProp]);

                }

                output.Write(spriteInfo.SpriteProperties.Keys.Count);
                foreach(string spritePropKey in spriteInfo.SpriteProperties.Keys)
                {
                    WriteString(output, spritePropKey);
                    WriteString(output, spriteInfo.SpriteProperties[spritePropKey]);
                }

                output.Write(spriteInfo.CollisionProperties.Keys.Count);
                foreach(string collPropKey in spriteInfo.CollisionProperties.Keys)
                {
                    WriteString(output, collPropKey);
                    WriteString(output, spriteInfo.CollisionProperties[collPropKey]);
                }

                // Animations.
                output.Write(spriteInfo.HasAnimation);
                WriteAnimations(output, spriteInfo.Animation);                
            }
        }

        private static void WriteString(ContentWriter output, string data)
        {
            output.Write(data);
        }

        private static void WriteAnimations(ContentWriter output, AnimationInfo animInfo)
        {
            if(animInfo == null) return;

            WriteString(output, animInfo.TypeName);

            output.Write(animInfo.Properties.Keys.Count);
            foreach(string animProp in animInfo.Properties.Keys)
            {
                WriteString(output, animProp);
                WriteString(output, animInfo.Properties[animProp]);
            }

            output.Write(animInfo.NestedAnimations.Count);
            foreach(AnimationInfo nestedAnimInfo in animInfo.NestedAnimations)
            {
                WriteAnimations(output, nestedAnimInfo);
            }
        }



        public static void LoadSpawnPoints(XmlElement spawnPointsRoot, ref List<SpawnPointInfo> spawnPointInfoList)
        {
            foreach(XmlNode spawn in spawnPointsRoot.ChildNodes)
            {
                XmlElement childElement = spawn as XmlElement; // Spawn.
                if(childElement == null)
                    continue;

                SpawnPointInfo spawnInfo = new SpawnPointInfo();
                
                int i = 0;
                foreach(XmlAttribute attribute in childElement.Attributes)
                {
                    spawnInfo.Properties.Add(attribute.Name, attribute.Value);
                    //Log.Instance.LogMessage(i.ToString() + " " + attribute.Value.ToString());
                    ++i;
                }

                spawnPointInfoList.Add(spawnInfo);
            }
        }

        public static void WriteSpawnPoints(ContentWriter output, ref List<SpawnPointInfo> spawnPointInfoList)
        {
            if(spawnPointInfoList == null) return;

            WriteString(output, "SpawnPoints");

            output.Write(spawnPointInfoList.Count);
            foreach(SpawnPointInfo spawnPoint in spawnPointInfoList)
            {                
                WriteString(output, "Spawn");

                output.Write(spawnPoint.Properties.Count);
                foreach(string key in spawnPoint.Properties.Keys)
                {
                    WriteString(output, key);
                    WriteString(output, spawnPoint.Properties[key]);
                }
            }
        }
    }
}
